--[[ 长空超少年脚本,作用是显示坐标和在坐标位置显示一个红色方块
  可作为cave stg游戏的模版
  
  坐标特点是分2个字节,高位把屏幕总长分4份,低位是奇特的局部修正,
  目前只是拟合了一下,具体算法还是不明朗,很奇葩

  By setycyas @2025-01-24
]]

-- 打包成GAME模块,最后导出
local GAME = {
  -- 横坐标纵坐标内存地址
  X_ADDR_HIGH = 0x102466,
  X_ADDR_LOW = 0x102467,
  Y_ADDR_HIGH = 0x102468,
  Y_ADDR_LOW = 0x102469,
  --火力等级地址
  SHOT_ADDR = 0x10272B,
  --CHARGE_ADDR = 0x102752, --蓄力,但冷却时会过早恢复,可能有其他数值
  -- 残机和炸弹地址
  LIFE_ADDR = 0x10254F,
  BOMB_ADDR = 0x102750,
  -- 自机中心方块的半长半高,单位为MAME的屏幕比例
  BOX_HALF_WIDTH = 0.005,
  BOX_HALF_HEIGHT = 0.005,
  HEIGHT_OFFSET = 0.02,
  -- 两个十字方块的半长半高
  XBOX_HALF_WIDTH = 0.032,
  XBOX_HALF_HEIGHT = 0.0065,
  YBOX_HALF_WIDTH = 0.0065,
  YBOX_HALF_HEIGHT = 0.035,
  -- 中心方块的边框颜色和中心颜色
  BOX_BORDER_COLOR = 0x88ff0000,
  BOX_COLOR = 0x88ff0000,
  -- 十字方块的边框颜色和中心颜色
  CROSS_BORDER_COLOR = 0x99ff00ff,
  CROSS_COLOR =  0x660000ff,
  -- mame api用的对象
  mem = manager.machine.devices[':maincpu'].spaces['program'],
  container = manager.machine.screens[":screen.0"].container,
  ui_container = manager.machine.render.ui_container,
}

-- 刷新设备,成功获取设备返回true,否返回false
function GAME.refreshDevices()
  GAME.mem = manager.machine.devices[':maincpu'].spaces['program']
  GAME.container = manager.machine.screens[":screen.0"].container
  GAME.ui_container = manager.machine.render.ui_container
  
  if (GAME.mem and GAME.container and GAME.ui_container) then
    return true
  else
    return false
  end
end

-- 坐标变换函数,从得到的坐标变为屏幕显示位置(是个比例),返回0.0-1.0的浮点数,
-- 后期游戏可能很复杂,需要根据游戏的情况手动操作变化
function GAME.getX()
  local xhigh, xlow, result
  xhigh = GAME.mem:read_u8(GAME.X_ADDR_HIGH)
  xlow = GAME.mem:read_u8(GAME.X_ADDR_LOW)
  result = xhigh/60.0 -- 60=240/4
  
  if (xlow > 200) then
    xlow = 200
  end
  if (xlow > 0) then
    result = result+(xlow-56)/11520.0 -- 11520=48*240
  end
  
  return result
end

function GAME.getY()
  local ylow, yhigh, result
  ylow = GAME.mem:read_u8(GAME.Y_ADDR_LOW)
  yhigh = GAME.mem:read_u8(GAME.Y_ADDR_HIGH)
  result = yhigh/80.0 -- 80=320/4
  
  result = result+ylow/15360.0 -- 15360.0=48*320
  return (result+GAME.HEIGHT_OFFSET)
end

-- 数据显示,指定位置和颜色,然后是可变的多个显示数据
function GAME.showInfo(position, color, ...)
  local count = select("#", ...)
  
  for i = 1, count do
    local arg = select(i, ...)
    GAME.ui_container:draw_text(position, 1.01-0.05*i, arg, color, 0xFF839496)
  end
  
end

-- 显示自机的几个方框,xfloat,yfloat是浮点数坐标
function GAME.showSqua(xfloat, yfloat)

  if (xfloat > 0.0) and (yfloat > 0.0) then
    -- 十字形方框,貌似没有看得更清楚,暂时注释掉
    
    -- 横向框
    GAME.container:draw_box(
      yfloat-GAME.XBOX_HALF_HEIGHT,
      xfloat-GAME.XBOX_HALF_WIDTH,
      yfloat+GAME.XBOX_HALF_HEIGHT,
      xfloat+GAME.XBOX_HALF_WIDTH,
      GAME.CROSS_BORDER_COLOR, GAME.CROSS_COLOR
    )
    -- 竖向框
    GAME.container:draw_box(
      yfloat-GAME.YBOX_HALF_HEIGHT,
      xfloat-GAME.YBOX_HALF_WIDTH,
      yfloat+GAME.YBOX_HALF_HEIGHT,
      xfloat+GAME.YBOX_HALF_WIDTH,
      GAME.CROSS_BORDER_COLOR, GAME.CROSS_COLOR
    )
    
    -- 自机红点
    GAME.container:draw_box(
      yfloat-GAME.BOX_HALF_HEIGHT,
      xfloat-GAME.BOX_HALF_WIDTH,
      yfloat+GAME.BOX_HALF_HEIGHT,
      xfloat+GAME.BOX_HALF_WIDTH,
      GAME.BOX_BORDER_COLOR, GAME.BOX_COLOR
    )
  end
  
end

-- 主函数,绑定后每一帧执行一次该函数
function GAME.main()
  local xhigh, xlow, yhigh, ylow, shotLv, laserLv, life, bomb --内存数据
  local xfloat, yfloat -- 最终浮点数坐标

  -- 刷新设备,并判断当前帧能否操作
  if (not GAME.refreshDevices()) then
    return
  end

  -- 内存数据读取
  xhigh = GAME.mem:read_u8(GAME.X_ADDR_HIGH)
  xlow = GAME.mem:read_u8(GAME.X_ADDR_LOW)
  ylow = GAME.mem:read_u8(GAME.Y_ADDR_LOW)
  yhigh = GAME.mem:read_u8(GAME.Y_ADDR_HIGH)
  shotLv = GAME.mem:read_u8(GAME.SHOT_ADDR)
  life = GAME.mem:read_u8(GAME.LIFE_ADDR)
  bomb = GAME.mem:read_u8(GAME.BOMB_ADDR)
  -- 获取自己屏幕坐标
  xfloat = GAME.getX()
  yfloat = GAME.getY()
  
  -- 显示当前火力等级
  --GAME.showInfo(0.05, 0xFF000000, string.format("SHOT=%d LASER=%d", shotLv, laserLv))
  -- 显示坐标
  --[[
  GAME.showInfo(0.05, 0xFF000000, 
    string.format("xlow=%d xhigh=%d ylow=%d yhigh=%d",
      xlow, xhigh, ylow, yhigh
    )
  )
  GAME.ui_container:draw_text(0.6, 0.9, 
    string.format("xlow=%d xhigh=%d \n ylow=%d yhigh=%d",
      xlow, xhigh, ylow, yhigh
    ), 
    0xFF000000, 0xFF839496
  )
  ]]
  -- 显示火力等级和雷
  GAME.ui_container:draw_text(0.6, 0.96, 
    string.format("pow=%d bomb=%d", shotLv, bomb),
    0xFF000000, 0xFF839496
  )
  -- 显示炸弹残机等级
  --[[
  GAME.ui_container:draw_text(0.05, 0.05, 
    string.format("LIFE=%d BOMB=%d", life, bomb), 
    0xFF000000, 0xFF839496
  )
  ]]
  -- 显示角色中心方块
  GAME.showSqua(xfloat, yfloat)
  
end

-- 绑定每一帧执行的函数
emu.register_frame_done(GAME.main, "frame")

return GAME
